package com.liliudong.template.biz.service.sys.impl;

import cn.hutool.core.collection.CollUtil;
import com.liliudong.template.biz.mapper.sys.SysRoleMapper;
import com.liliudong.template.biz.service.sys.SysRoleDeptService;
import com.liliudong.template.biz.service.sys.SysRoleMenuService;
import com.liliudong.template.biz.service.sys.SysRoleService;
import com.liliudong.template.common.constant.ExMessage;
import com.liliudong.template.common.constant.SecurityConst;
import com.liliudong.template.common.convert.sys.SysRoleConvert;
import com.liliudong.template.common.request.sys.SysRoleAddRequest;
import com.liliudong.template.common.request.sys.SysRoleModifyRequest;
import com.liliudong.template.common.entity.sys.SysRole;
import com.liliudong.template.common.entity.sys.SysUserRole;
import com.liliudong.template.common.exception.BizException;
import com.liliudong.template.common.response.sys.SysRoleDetailResponse;
import com.liliudong.template.common.response.sys.SysRolePageResponse;
import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.query.QueryWrapper;
import com.mybatisflex.spring.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

import static com.liliudong.template.common.entity.sys.table.SysRoleTableDef.SYS_ROLE;
import static com.liliudong.template.common.entity.sys.table.SysUserRoleTableDef.SYS_USER_ROLE;

/**
 * SysRoleService
 *
 * @author liudo
 * @version 1.0
 * @project template-backend
 * @date 2024/7/30 13:21:57
 */
@Service
@RequiredArgsConstructor
public class SysRoleServiceImpl extends ServiceImpl<SysRoleMapper, SysRole> implements SysRoleService {

    private final SysRoleMenuService sysRoleMenuService;

    private final SysRoleDeptService sysRoleDeptService;

    @Override
    public List<SysRole> listByUserIdIgnoreDataPermission(Long userId) {
        return queryChainIgnoreDataPermission()
                .select(SYS_ROLE.DEFAULT_COLUMNS)
                .innerJoin(SysUserRole.class)
                .on(SYS_ROLE.ID.eq(SYS_USER_ROLE.ROLE_ID))
                .where(SYS_USER_ROLE.USER_ID.eq(userId))
                .list();
    }

    @Override
    public Set<SysRole.DataScope> listDataScopeByUserIdIgnoreDataPermission(Long userId, boolean isAdmin) {
        if (isAdmin) {
            return Set.of(SysRole.DataScope.ALL);
        }
        if (Objects.isNull(userId)) {
            return Set.of();
        }
        return queryChainIgnoreDataPermission()
                .select(SYS_ROLE.DATA_SCOPE)
                .innerJoin(SysUserRole.class)
                .on(SYS_ROLE.ID.eq(SYS_USER_ROLE.ROLE_ID))
                .where(SYS_USER_ROLE.USER_ID.eq(userId))
                .list()
                .stream()
                .map(SysRole::getDataScope)
                .collect(Collectors.toSet());
    }

    @Override
    @Transactional
    public void addOne(SysRoleAddRequest sysRoleAddRequest) {
        SysRole sysRole = SysRoleConvert.INSTANCE.addDto2Entity(sysRoleAddRequest);
        List<Long> deptIds = sysRoleAddRequest.getDeptIds();
        List<Long> menuIds = sysRoleAddRequest.getMenuIds();
        if (Objects.equals(sysRole.getDataScope(), SysRole.DataScope.CUSTOMIZE) &&
                CollUtil.isEmpty(deptIds)) {
            throw new BizException(ExMessage.DEPT_EMPTY);
        }
        // 校验角色编码是否重复
        this.checkPermission(sysRole.getPermission());
        // 保存角色信息
        this.save(sysRole);
        // 保存角色部门关联信息
        sysRoleDeptService.saveBatchWithRoleId(sysRole.getId(), deptIds);
        // 保存角色菜单关联信息
        sysRoleMenuService.saveBatchWithRoleId(sysRole.getId(), menuIds);
    }

    @Override
    @Transactional
    public void deleteById(Long id) {
        // 删除角色信息
        this.removeById(id);
        // 删除角色部门关联信息
        sysRoleDeptService.removeByRoleId(id);
        // 删除角色菜单关联信息
        sysRoleMenuService.removeByRoleId(id);
    }

    @Override
    @Transactional
    public void modifyById(Long id, SysRoleModifyRequest sysRoleModifyRequest) {
        SysRole newSysRole = SysRoleConvert.INSTANCE.modifyDto2Entity(sysRoleModifyRequest);
        newSysRole.setId(id);
        List<Long> deptIds = sysRoleModifyRequest.getDeptIds();
        List<Long> menuIds = sysRoleModifyRequest.getMenuIds();

        boolean isCustomize = Objects.equals(SysRole.DataScope.CUSTOMIZE, sysRoleModifyRequest.getDataScope());
        if (isCustomize && CollUtil.isEmpty(deptIds)) {
            throw new BizException(ExMessage.DEPT_EMPTY);
        }
        // 校验角色编码
        this.checkPermission(newSysRole.getPermission());
        // 更新角色信息
        this.updateById(newSysRole);
        // 更新角色部门关联信息
        sysRoleDeptService.removeByRoleId(id);
        if (isCustomize) {
            sysRoleDeptService.saveBatchWithRoleId(id, deptIds);
        }
        // 更新角色菜单关联信息
        sysRoleMenuService.removeByRoleId(id);
        sysRoleMenuService.saveBatchWithRoleId(id, menuIds);
    }

    @Override
    public Page<SysRolePageResponse> queryPage(Long page, Long size) {
        return queryChain().pageAs(Page.of(page, size), SysRolePageResponse.class);
    }

    @Override
    public SysRoleDetailResponse detailById(Long id) {
        SysRoleDetailResponse sysRoleDetailVO = this.getOneAs(QueryWrapper.create().where(SYS_ROLE.ID.eq(id)), SysRoleDetailResponse.class);
        if (Objects.isNull(sysRoleDetailVO)) {
            throw new BizException(ExMessage.ROLE_NOT_EXIST);
        }
        // 角色部门
        if (sysRoleDetailVO.getDataScope() == SysRole.DataScope.CUSTOMIZE) {
            Set<Long> deptIds = sysRoleDeptService.listDeptIdsByRoleId(id);
            sysRoleDetailVO.setDeptIds(deptIds);
        }
        // 角色菜单
        boolean isAdmin = Objects.equals(sysRoleDetailVO.getPermission(), SecurityConst.SUPER_ADMIN_ROLE_PERMISSION);
        Set<Long> menuIds = sysRoleMenuService.listMenuIdsByRoleId(id, isAdmin);
        sysRoleDetailVO.setMenuIds(menuIds);
        return sysRoleDetailVO;
    }

    /**
     * 检查权限
     *
     * @param permission 权限
     */
    private void checkPermission(String permission) {
        boolean exists = queryChain()
                .where(SYS_ROLE.PERMISSION.eq(permission))
                .exists();
        if (exists) {
            throw new BizException(ExMessage.ROLE_PERMISSION_REPEAT);
        }
    }
}
